package com.leyou.sh.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.sh.common.dto.PageDTO;
import com.leyou.sh.common.exception.LyException;
import com.leyou.sh.common.utils.JsonUtils;
import com.leyou.sh.item.dto.SkuDTO;
import com.leyou.sh.item.dto.SpecParamDTO;
import com.leyou.sh.item.dto.SpuDTO;
import com.leyou.sh.item.dto.SpuDetailDTO;
import com.leyou.sh.item.entity.Category;
import com.leyou.sh.item.entity.Sku;
import com.leyou.sh.item.entity.Spu;
import com.leyou.sh.item.entity.SpuDetail;
import com.leyou.sh.item.mapper.SpuMapper;
import com.leyou.sh.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author balisong_fcs
 * @date 2020/12/28 22:34
 * @desc
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {
    @Autowired
    private SpuDetailService spuDetailService;
    @Autowired
    private SkuService skuService;
    @Autowired
    private SpecParamService paramService;
    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;

    /**
     * 同时查询分类,并将字段展示
     * @param brandId
     * @param categoryId
     * @param id
     * @param page
     * @param rows
     * @param saleable
     * @return
     */
    @Override
    public PageDTO<SpuDTO> querySpuByPage(Long brandId, Long categoryId, Long id, Integer page, Integer rows, Boolean saleable) {

        IPage<Spu> iPage = new Page<Spu>(page, rows);
        //先分页查询spu,并且整合动态sql查询
        this.page(iPage, new QueryWrapper<Spu>()
                .eq(null != categoryId, "cid3", categoryId)
                .eq(null != brandId, "brand_id", brandId)
                .eq(saleable != null, "saleable", saleable)
                .eq(null != id, "id", id)
        );

        //spuEntity==>spuDTO
        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(iPage.getRecords());

        //循环给dto赋值，brandName以及categoryName
        spuDTOS.forEach(spuDTO -> {
            spuDTO.setBrandName(this.brandService.getById(spuDTO.getBrandId()).getName());

            //TODO 考虑缓存问题，
            //根据分类的id集合查询分类集合，并取出每个分类的名称，并拼接字符串
            String names = this.categoryService.listByIds(spuDTO.getCategoryIds())
                    .stream().map(Category::getName)
                    .collect(Collectors.joining("/"));
            //StringUtils.join(array,分隔符)
            spuDTO.setCategoryName(names);
        });

        return new PageDTO<SpuDTO>(iPage.getTotal(), iPage.getPages(), spuDTOS);
    }

    /**
     * @param spuDTO 保留
     * @param //skuDTOList 错误
     * @param //spuDetailDTO 错误
     */

    @Override
    @Transactional
    public void saveSpu(SpuDTO spuDTO) {
        Spu spu = spuDTO.toEntity(Spu.class);
        // 存入spu,并主键回显
        this.save(spu);
        if (CollectionUtils.isEmpty(spuDTO.getSkus())) {
            throw new LyException(400, "sku不能为空");
        }
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        this.spuDetailService.save(spuDetail);
        /**
         * 维护商品表里的spu 字段关联和是否上架的字段标记
         */
        List<Sku> skuList = spuDTO.getSkus().stream().map(skuDTO -> {
            Sku sku = skuDTO.toEntity(Sku.class);
            sku.setSaleable(true);
            sku.setSpuId(spu.getId());
            return sku;
        }).collect(Collectors.toList());
        this.skuService.saveBatch(skuList);
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        //判断根据id指定具体的进行跟新
        Long id = spuDTO.getId();
        if (null != id) {
            this.updateById(spuDTO.toEntity(Spu.class));
        }
        //若细节描述项修改了,则根据传回的数据进行修改
        //若为空,则表示前端该项没有进行修改,则不跟新
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        if (null != spuDetailDTO) {
            this.spuDetailService.updateById(spuDetailDTO.toEntity(SpuDetail.class));
        }

        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        //sku的集合,不为空说明有修改或删除/新增需求
        if (null != skuDTOList && 0 != skuDTOList.size()) {
            Map<Boolean, List<Sku>> listMap = skuDTOList.stream().map(skuDTO -> skuDTO.toEntity(Sku.class))
                    .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));

            //前端勾选了启用.则salebale为true,表示需要跟新或修改
            List<Sku> toAddOrUpdate = listMap.get(true);
            if (!CollectionUtils.isEmpty(toAddOrUpdate)) {
                //mybatis-plus 提供的批量修改或新增的api
                this.skuService.saveOrUpdateBatch(toAddOrUpdate);
            }
            //若尾勾选,则需要删除掉
            List<Sku> toDelete = listMap.get(false);
            if (!CollectionUtils.isEmpty(toDelete)) {
                //map()括号内类层面调用方法返回对应参数进行处理--
                this.skuService.removeByIds(toDelete.stream().map(Sku::getId).collect(Collectors.toList()));
            }
        }


    }

    @Override
    public List<SpecParamDTO> querySpecParamValue(Long id, Boolean searching) {
        //根据spuid 获取分类id
        Long categoryId = this.getById(id).getCid3();
        //根据分类id查询得到参数集合
        List<SpecParamDTO> paramDTOS = this.paramService.querySpecParamByCidAndGid(categoryId, null, null);
        //根据spu的id 获取参数详情的specificationJson对象
        String specification = this.spuDetailService.getById(id).getSpecification();
        //将json对象处理为map
        Map<Long, Object> paramMap = JsonUtils.nativeRead(specification, new TypeReference<Map<Long, Object>>() {
        });
        paramDTOS.forEach(specParamDTO -> specParamDTO.setValue(paramMap.get(specParamDTO.getId())));
        return paramDTOS;
    }

    @Autowired
    private AmqpTemplate amqpTemplate;
    /**
     * 修改商品上下架
     *  后引入了rabbitmq消息队列,进行上下架操作时发送消息到mq队列.操作es search操作索引库更新
     * @param id
     * @param saleable
     */
    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        this.updateById(spu);

        Sku sku = new Sku();
        sku.setSaleable(saleable);

        this.skuService.update(sku, new QueryWrapper<Sku>().eq("spu_id", id));
        /**
         * 消息发送三要素: 交换机/routingKey/消息
         */
        String routingKey = saleable ? "item.up" : "item.down";
        this.amqpTemplate.convertAndSend("jhj", routingKey, id);
    }

    @Override
    public SpuDTO queryById(Long id) {
        SpuDTO spuDTO = new SpuDTO(this.getById(id));
        if (null == spuDTO) {
            throw new LyException(204, "该id查询对应信息为空");
        }
        spuDTO.setSkus(this.skuService.querySkuBySpuId(id));
        spuDTO.setSpuDetail(this.spuDetailService.querySpuDetailBySpuid(id));
        return spuDTO;
    }

    @Override
    public SpuDTO querySpuById(Long spid) {
        return new SpuDTO(this.getById(spid));
    }
}
